﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Windows.Forms;
using DevelopTool.Bll.DbBlls;
using DevelopTool.Common;
using DevelopTool.Forms.BaseForms;
using DevelopTool.Forms.CommonControls;
using DevelopTool.Forms.CommonForms;
using DevelopTool.Forms.LodingForm;
using DevelopTool.Model;
using DevelopTool.Model.DbModels;
using Sunny.UI;

namespace DevelopTool.Forms.DbForms
{
    /// <summary>
    /// 数据库全文检索
    /// </summary>
    public partial class DbSearchForm : BaseUIPage
    {
        /// <summary>
        /// 数据库通用操作类
        /// </summary>
        private DbManagerBll dbManagerBll;

        #region 搜索参数

        /// <summary>
        /// 数据库连接信息
        /// </summary>
        private DbInfo dbInfo;


        /// <summary>
        /// 搜索范围
        /// </summary>
        private string searchType;

        /// <summary>
        /// 搜索模式
        /// </summary>
        private string matchingMode = "全字匹配";

        /// <summary>
        /// 是否忽略大小写
        /// </summary>
        private bool ignoreCase = true;

        /// <summary>
        /// 是否统计行数
        /// </summary>
        private bool isCount = false;

        /// <summary>
        /// 数据类型集合
        /// </summary>
        private List<string> dataTypeList;
        #endregion


        #region 后台任务属性

        /// <summary>
        /// 总任务开始时间
        /// </summary>
        private DateTime taskstartTime;


        /// <summary>
        /// 检测任务状态的计时器
        /// </summary>
        private System.Windows.Forms.Timer taskTimer;


        /// <summary>
        /// 当前任务开始时间
        /// </summary>
        private DateTime nowTaskStartTime;

        /// <summary>
        /// 搜索结果
        /// </summary>
        private DataTable resultTable;

        #endregion

        /// <summary>
        /// DataGridView列信息集合
        /// </summary>
        private List<DataGridColumn> dataGridColumns = new List<DataGridColumn>()
              {
             { new DataGridColumn("KEYWORD"){ColumnText="搜索关键字",Width=0}},
             { new DataGridColumn("OWNER"){ColumnText="实例",Width=100,ColumnType=ColumnType.DefaultFilter}},
             { new DataGridColumn("NAME"){ColumnText="对象名称",Width=0,ColumnType=ColumnType.DefaultFilter|ColumnType.RowMain,}},
                { new DataGridColumn("TEXT"){ColumnText="匹配数据",Width=0,ColumnType=ColumnType.DefaultFilter|ColumnType.LongText,ShowFormProperty=new ShowFormProperty(){
                BaseNameColumn="NAME",ShowTextLength=40
                }}},
                { new DataGridColumn("COUNT"){ColumnText="行数",Width=-1,ColumnType = ColumnType.DefaultFilter}},
                { new DataGridColumn("TYPE"){ColumnText="搜索对象",Width=0,ColumnType = ColumnType.DefaultFilter}},
                { new DataGridColumn("COLUMN"){ColumnText="对象匹配字段",Width=-1,ColumnType = ColumnType.DefaultFilter}},
              };

        public DbSearchForm()
        {
            InitializeComponent();
        }


        private void SearchForm_Load(object sender,EventArgs e)
        {
            this.Disposed += this.DbSearchForm_Disposed;

            uiToolTip.SetToolTip(this.txtKeyword,@"
                                1、可输入多个关键字，用;分割。
                                2、日期必须为yyyy/MM/dd格式，注意-符号。
                                ");

            this.rdoGroupMatchingMode.SelectedIndex = 1;


            //初始化任务报告DataTable
            resultTable = new DataTable("ResultTable");
            resultTable.Columns.Add("KEYWORD",typeof(string));
            resultTable.Columns.Add("OWNER",typeof(string));
            resultTable.Columns.Add("NAME",typeof(string));
            resultTable.Columns.Add("TEXT",typeof(string));
            resultTable.Columns.Add("COUNT",typeof(int));
            resultTable.Columns.Add("TYPE",typeof(string));
            resultTable.Columns.Add("COLUMN",typeof(string));

            this.dataDisplayControl.BindData(resultTable,this.dataGridColumns);

            this.uiGroupBoxtxtTableListStr.Padding = new Padding(0,15,0,0);
        }




        /// <summary>
        /// 数据库连接下拉框选择事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dbinfoSelectCombo1_DbInfoSelected(object sender,DbinfoEventArgs e)
        {
            if(e.DbInfo == null || !e.IsConnect)
            {
                this.dbInfo = null;
                this.dbManagerBll = null;
                this.cboDatabase.Enabled = false;
                this.rdoGroupSearchType.Enabled = false;
                this.rdoGroupMatchingMode.Enabled = false;
                this.cboStype.Enabled = false;
                this.txtKeyword.Enabled = false;
                this.cboIgnoreCase.Enabled = false;
                this.cboIsCount.Enabled = false;
                return;
            }

            this.dbInfo = e.DbInfo;

            this.dbManagerBll = new DbManagerBll(dbInfo);

            #region 初始化数据库实例下拉框数据
            cboDatabase.Enabled = true;
            DataTable dataBaseNameAll = this.dbManagerBll.GetAllDataBaseList();//获取所有数据库实例集合

            cboDatabase.DataGridView.Init();
            cboDatabase.DataGridView.AddColumn("实例","DatabaseName");
            cboDatabase.DataGridView.ReadOnly = true;
            cboDatabase.ShowFilter = true;
            cboDatabase.DataGridView.MultiSelect = true;//设置可多选
            cboDatabase.ValueChanged += delegate (object senderobj,object value)
            {
                cboDatabase.Text = string.Empty;
                if(value != null && value is DataGridViewSelectedRowCollection collection)
                {
                    foreach(var item in collection)
                    {
                        DataGridViewRow row = (DataGridViewRow)item;
                        cboDatabase.Text += row.Cells["实例"].Value.ToString();
                        cboDatabase.Text += ";";
                    }
                }
            };
            cboDatabase.DataGridView.DataSource = dataBaseNameAll;
            #endregion

            this.rdoGroupSearchType.Enabled = true;
            this.cboStype.Enabled = true;
            this.txtKeyword.Enabled = true;
            this.rdoGroupMatchingMode.Enabled = true;
            this.cboIgnoreCase.Enabled = true;
            this.cboIsCount.Enabled = true;
        }


        /// <summary>
        /// 搜索模式单选事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="index"></param>
        /// <param name="text"></param>
        private void rdoGroupMatchingMode_ValueChanged(object sender,int index,string text)
        {
            if(!rdoGroupMatchingMode.ContainsFocus) return;

            this.matchingMode = text;
        }


        /// <summary>
        /// 是否忽略大小写
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void cboIgnoreCase_CheckedChanged(object sender,EventArgs e)
        {
            this.ignoreCase = this.cboIgnoreCase.Checked;
        }


        private void cboIsCount_CheckedChanged(object sender,EventArgs e)
        {
            this.isCount = this.cboIsCount.Checked;
        }

        /// <summary>
        /// 搜索按钮事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSearch_Click(object sender,EventArgs e)
        {
            if(this.backgroundWorker.IsBusy)//正在运行
            {
                this.btnSearch.Text = "搜索";
                this.btnSearch.Symbol = 61515;
                this.btnSearch.Enabled = false;
                backgroundWorker.CancelAsync();//循环完成后，停止后台任务
            }
            else
            {
                if(this.dbInfo == null)
                {
                    this.ShowWarningNotifier("请选择数据库连接");
                    return;
                }


                if(string.IsNullOrEmpty(this.txtKeyword.Text))
                {
                    this.ShowWarningNotifier("请输入关键字");
                    return;
                }

                if(string.IsNullOrEmpty(this.searchType))
                {
                    this.ShowWarningNotifier("请选择搜索范围");
                    return;
                }

                #region 实例集合
                List<string> dataBaseList = new List<string>();

                if(string.IsNullOrEmpty(this.cboDatabase.Text))
                {
                    LoadingHelper.ShowLoading("加载所有实例",() =>
                    {
                        DataTable dataBaseData = this.dbManagerBll.GetAllDataBaseList();

                        foreach(DataRow dataBaseDataRow in dataBaseData.Rows)
                        {
                            string dataBaseName = dataBaseDataRow["DatabaseName"].ToString();
                            dataBaseList.Add(dataBaseName);
                        }
                    });
                }
                else
                {
                    dataBaseList.AddRange(this.cboDatabase.Text.Split(";",true));
                }
                #endregion

                List<Tuple<string,string>> taskList = new List<Tuple<string,string>>();

                if(this.searchType == "结构")
                {
                    //nodes为TreeView的所有节点，需循环判断
                    foreach(TreeNode item in cboStype.Nodes)
                    {
                        if(item.Checked)
                            taskList.Add(new Tuple<string,string>("",item.Text));
                    }

                    if(taskList.Count <= 0)
                    {
                        this.ShowWarningNotifier("请至少选择一个搜索对象");
                        return;
                    }
                }
                else if(this.searchType == "数据")
                {
                    //nodes为TreeView的所有节点，需循环判断
                    this.dataTypeList = new List<string>();
                    foreach(TreeNode topNode in cboStype.Nodes)
                    {
                        foreach(TreeNode item in topNode.Nodes)
                        {
                            if(item.Checked)
                                this.dataTypeList.Add(item.Text);
                        }
                    }
                    if(this.dataTypeList.Count <= 0)
                    {
                        this.ShowWarningNotifier("请至少选择一个数据类型");
                        return;
                    }

                    LoadingHelper.ShowLoading("加载相关表",() =>
                    {
                        if(!string.IsNullOrEmpty(this.txtTableListStr.Text) && this.txtTableListStr.Tag != null)
                        {
                            DataTable dt = (DataTable)this.txtTableListStr.Tag;
                            dt.DefaultView.RowFilter = "NUM_ROWS>0";
                            dt.DefaultView.Sort = "NUM_ROWS desc";
                            dt = dt.DefaultView.ToTable();
                            foreach(DataRow dataRow in dt.Rows)
                            {
                                taskList.Add(new Tuple<string,string>(dataRow["OWNER"].ToString(),dataRow["TABLE_NAME"].ToString()));
                            }
                        }
                        else
                        {
                            foreach(string dataBaseName in dataBaseList)
                            {
                                DataTable tableData = this.dbManagerBll.GetTables(dataBaseName);
                                tableData.DefaultView.RowFilter = "NUM_ROWS>0";
                                tableData.DefaultView.Sort = "NUM_ROWS desc";
                                tableData = tableData.DefaultView.ToTable();
                                foreach(DataRow tableDataRow in tableData.Rows)
                                {
                                    taskList.Add(new Tuple<string,string>(dataBaseName,tableDataRow["TABLE_NAME"].ToString()));
                                }
                            }
                        }

                        if(taskList.Count <= 0)
                        {
                            this.ShowWarningNotifier("没有需要搜索的表");
                            return;
                        }
                    });
                }

                this.btnSearch.Text = "停止搜索";
                this.btnSearch.Symbol = 61517;

                this.taskstartTime = DateTime.Now;

                resultTable.Clear();

                backgroundWorker.RunWorkerAsync(taskList);//开始后台任务          

                //创建并启动检测任务状态的计时器
                taskTimer = new System.Windows.Forms.Timer
                {
                    Interval = 1000,
                    Enabled = true
                };
                taskTimer.Tick += TaskTimer_Tick;
            }
        }

        /// <summary>
        /// 检测任务状态的计时器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void TaskTimer_Tick(object sender,EventArgs e)
        {
            //当前任务耗时
            TimeSpan timeSpan = new TimeSpan(nowTaskStartTime.Ticks).Subtract(new TimeSpan(DateTime.Now.Ticks)).Duration();
            lblTime.Text = timeSpan.TotalSeconds.ToDouble(1).ToString();

            //总任务耗时
            TimeSpan timeSpanTotal = new TimeSpan(taskstartTime.Ticks).Subtract(new TimeSpan(DateTime.Now.Ticks)).Duration();
            lblTotalTime.Text = timeSpanTotal.TotalSeconds.ToDouble(1).ToString();
        }

        /// <summary>
        /// 获取关键字集合
        /// </summary>
        /// <returns></returns>
        private List<string> GetKeywordList()
        {
            var list = this.txtKeyword.Text.Split(";",true);
            return list.Select(it => it.Trim()).Where(it => !string.IsNullOrEmpty(it)).ToList();
        }

        #region 后台任务
        /// <summary>
        /// 开始后台任务
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_DoWork(object sender,DoWorkEventArgs e)
        {
            List<Tuple<string,string>> taskList = e.Argument as List<Tuple<string,string>>;//任务列表
            List<string> keywordList = GetKeywordList();//搜索关键字

            int taskexecutedNum = 0;//已执行完成任务数


            foreach(Tuple<string,string> task in taskList)
            {
                if(this.backgroundWorker.CancellationPending) break;

                this.nowTaskStartTime = DateTime.Now;//当前任务开始时间

                this.Invoke(new Action(() =>
                {
                    txtNowTaskName.Text = task.Item2;//当前任务名

                    lblTaskCount.Text = taskList.Count + "/" + taskexecutedNum;//剩余任务数
                }));

                try
                {
                    DataTable result = new DataTable();
                    if(this.searchType == "结构")
                    {
                        result = dbManagerBll.SearchTypeContent(task.Item1,task.Item2,keywordList,this.matchingMode,this.ignoreCase);//搜索结构,这是核心~                   
                    }
                    else if(this.searchType == "数据")
                    {
                        result = dbManagerBll.SearchDataContent(task.Item1,task.Item2,this.dataTypeList,keywordList,this.matchingMode,this.ignoreCase,this.isCount);//搜索数据,这是核心~
                    }

                    backgroundWorker.ReportProgress(0,result);//报告状态，展示结果

                }
                catch(Exception ex)
                {
                    LogHelper.WriteErrLog(ex);
                }
                finally
                {
                    taskexecutedNum++;
                }

                this.BeginInvoke(new Action(() =>
                {
                    lblTaskCount.Text = taskList.Count + "/" + taskexecutedNum;//剩余任务数
                }));
            }
        }


        /// <summary>
        /// 线程报告进度
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_ProgressChanged(object sender,ProgressChangedEventArgs e)
        {
            var results = e.UserState as DataTable;
            resultTable.Merge(results);
        }


        /// <summary>
        /// 线程完成
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e)
        {
            this.btnSearch.Text = "搜索";
            this.btnSearch.Symbol = 61442;
            this.btnSearch.Enabled = true;

            this.BeginInvoke(new Action(() =>
            {
                //停止计时器
                this.taskTimer.Stop();
                this.taskTimer.Dispose();

                txtNowTaskName.Text = string.Empty;
                lblTime.Text = string.Empty;
            }));

            //手动停止时，不推送消息
            if(!backgroundWorker.CancellationPending)
            {
                if(Setting.System.SendMsgModule.Contains("DbSearchComplete"))
                    FeiShuMsgHelper.SendCardMsgAsync($"结果：{resultTable.Rows.Count}",$"数据库全文检索完成");
            }
        }

        #endregion


        /// <summary>
        /// 搜索范围单选事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="index"></param>
        /// <param name="text"></param>
        private void rdoGroupSearchType_ValueChanged(object sender,int index,string text)
        {
            this.cboStype.Nodes.Clear();
            this.searchType = text;
            if(text == "结构")
            {
                this.lblStypeText.Text = "搜索对象（结构）（必选）";

                this.cboStype.Nodes.Add("表");
                this.cboStype.Nodes.Add("视图");
                this.cboStype.Nodes.Add("表字段");
                this.cboStype.Nodes.Add("视图字段");
                this.cboStype.Nodes.Add("函数");
                this.cboStype.Nodes.Add("存储过程");
                this.cboStype.Nodes.Add("包");
                this.cboStype.Nodes.Add("触发器");
                this.cboStype.Nodes.Add("job");
                this.cboStype.Nodes.Add("同义词");
                this.cboStype.Nodes.Add("用户");
                this.cboStype.Nodes.Add("报表");
                this.cboStype.Nodes.Add("序列");

                this.uiGroupBoxtxtTableListStr.Visible = false;
            }
            else if(text == "数据")
            {
                this.lblStypeText.Text = "搜索数据类型（必选）";

                ////数据类型集合
                Dictionary<string,List<string>> pairs = new Dictionary<string,List<string>>();
                pairs.Add("字符串",new List<string>
                {
                    "VARCHAR2",
                    "CHAR",
                    "NCHAR",
                    "NVARCHAR2",
                });
                pairs.Add("长文本",new List<string>
                {
                    "CLOB",
                    "NCLOB",
                });
                pairs.Add("字节文本",new List<string>
                {
                    "BLOB",
                });
                pairs.Add("数值",new List<string>
                {
                    "FLOAT",
                    "NUMBER",
                    "INTEGER",
                    "DECIMAL",
                });
                pairs.Add("日期",new List<string>
                {
                    "DATE",
                    "TIMESTAMP(6)",
                    "TIMESTAMP",
                });
                //pairs.Add("过时长文本", new List<string>
                //{
                //    "LONG",
                //});


                foreach(var pair in pairs)
                {
                    TreeNode top = this.cboStype.Nodes.Add(pair.Key);
                    foreach(string type in pair.Value)
                    {
                        top.Nodes.Add(type);
                    }
                }

                this.uiGroupBoxtxtTableListStr.Visible = true;
            }

        }



        private void txtTableListStr_ButtonClick(object sender,EventArgs e)
        {
            if(this.dbManagerBll == null) return;

            List<DataGridColumn> searchdataGridColumns = new List<DataGridColumn>()
              {
              { new DataGridColumn("TABLE_NAME"){ColumnText="表名",Width=0,ColumnType = ColumnType.DefaultFilter}},
                { new DataGridColumn("NUM_ROWS"){ColumnText="数据总计",Width=-1}},
                { new DataGridColumn("COMMENTS"){ColumnText="注释",Width=0,ColumnType = ColumnType.DefaultFilter}},
                { new DataGridColumn("OWNER"){ColumnText="实例",Width=100,ColumnType = ColumnType.DefaultFilter}},
                { new DataGridColumn("TEXT"){ColumnText="建表sql",Width=-1,ColumnType =ColumnType.Hide }},
                { new DataGridColumn("REFCOUNT"){ColumnText="依赖数量",Width=-1,ColumnType =ColumnType.Hide}},
                { new DataGridColumn("TABLESPACE_NAME"){ColumnText="表空间",Width=0}},
                { new DataGridColumn("LAST_ANALYZED"){ColumnText="最近分析日期",Width=150,ColumnType = ColumnType.Hide}}
              };


            DataTable tables = new DataTable("table");

            if(string.IsNullOrEmpty(this.cboDatabase.Text))
            {
                LoadingHelper.ShowLoading("加载所有表",() =>
                {
                    tables = this.dbManagerBll.GetTables();
                });
            }
            else
            {
                var dataBases = this.cboDatabase.Text.Split(";",true);
                LoadingHelper.ShowLoading("加载表",() =>
                {
                    foreach(string dataBaseName in dataBases)
                    {
                        DataTable tableData = this.dbManagerBll.GetTables(dataBaseName);
                        tables.Merge(tableData);
                    }
                });
            }

            tables.DefaultView.RowFilter = "NUM_ROWS>0";
            tables.DefaultView.Sort = "NUM_ROWS desc";
            tables = tables.DefaultView.ToTable();

            DataSelectForm tableSelectForm = new DataSelectForm("选择需要搜索的表",searchdataGridColumns,tables,(DataTable)this.txtTableListStr.Tag);

            if(tableSelectForm.ShowDialog() == DialogResult.OK)
            {
                this.txtTableListStr.Text = "已选" + tableSelectForm.SelectValues.Rows.Count + "个表";
                this.txtTableListStr.Tag = tableSelectForm.SelectValues;
            }
        }


        private void DbSearchForm_Disposed(object sender,EventArgs e)
        {
            try
            {
                this.backgroundWorker.CancelAsync();
                this.backgroundWorker.Dispose();
            }
            catch(Exception ex)
            {
                LogHelper.WriteErrLog(ex);
            }
        }
    }

}
